
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
using System.Text;

using Swaf;
using Swaf.BizObj;
using Swaf.BizRule;
using Swaf.Security;

namespace Syrinx
{
	public class CaptchaVerifierBizRules : Syrinx.BaseBizRules
	{
		public MediaStream getCaptchaImage(IApplication app, IRuleContext context, string textToEmbed)
		{
			MediaStream s = null;
			//Items to go into company settings for captcha options.
			int width = 300;
			int height = 100;
			string fontFamily = "Century Schoolbook";

			Bitmap bitmap = new Bitmap(width,height,PixelFormat.Format32bppArgb);
			Graphics g = Graphics.FromImage(bitmap);
			g.SmoothingMode = SmoothingMode.AntiAlias;
			Rectangle rect = new Rectangle(0, 0, width, height);

			// Fill in the background.
			HatchBrush hatchBrush = new HatchBrush(HatchStyle.SmallConfetti, Color.LightGray, Color.White);
			g.FillRectangle(hatchBrush, rect);

			// Set up the text font.
			SizeF size;
			float fontSize = rect.Height;
			Font font;
			// Adjust the font size until the text fits within the image.
			int desiredWidth = width + (int)(width * .3);
			do
			{
				font = new Font(fontFamily, fontSize--, FontStyle.Bold);
				size = g.MeasureString(textToEmbed, font);
			} while (size.Width > desiredWidth);

			// Set up the text format.
			StringFormat format = new StringFormat();
			format.Alignment = StringAlignment.Center;
			format.LineAlignment = StringAlignment.Center;

			// Create a path using the text and warp it randomly.
			Random random = new Random();
			GraphicsPath path = new GraphicsPath();
			path.AddString(textToEmbed, font.FontFamily, (int)font.Style, font.Size, rect, format);
			float v = 4F;
			PointF[] points =
			  {
				new PointF(random.Next(rect.Width) / v, random.Next(rect.Height) / v),
				new PointF(rect.Width - random.Next(rect.Width) / v, random.Next(rect.Height) / v),
				new PointF(random.Next(rect.Width) / v, rect.Height - random.Next(rect.Height) / v),
				new PointF(rect.Width - random.Next(rect.Width) / v, rect.Height - random.Next(rect.Height) / v)
			  };

			Matrix matrix = new Matrix();
			matrix.Translate(0F, 0F);
			path.Warp(points, rect, matrix, WarpMode.Perspective, 0F);

			// Draw the text.
			hatchBrush = new HatchBrush(
			  HatchStyle.LargeConfetti,
			  Color.LightGray,
			  Color.DarkGray);
			g.FillPath(hatchBrush, path);

			// Add some random noise.
			int m = Math.Max(rect.Width, rect.Height);
			for (int i = 0; i < (int)(rect.Width * rect.Height / 30F); i++)
			{
				int x = random.Next(rect.Width);
				int y = random.Next(rect.Height);
				int w = random.Next(m / 50);
				int h = random.Next(m / 50);
				g.FillEllipse(hatchBrush, x, y, w, h);
			}

			// Clean up.
			font.Dispose();
			hatchBrush.Dispose();
			g.Dispose();

			// Set the image.
			MemoryStream mem = new MemoryStream();
			bitmap.Save(mem, ImageFormat.Jpeg);
			mem.Seek(0, SeekOrigin.Begin);
			bitmap.Dispose();

			s = new MediaStream("jpg", mem, "");
			return s;
		}

		public string shouldShowUserVerification(IApplication app, IRuleContext context, string usage, IBizObj clientInfo)
		{
			bool getKey = true;
			string key = null;
			if (string.Compare(usage, "login", true) == 0)
				getKey = !(bool)CurrentUser.get("authenticated");
			else if (string.Compare(usage, "canedit", true) == 0)
				getKey = (bool)clientInfo.get("canEdit") && CurrentPrincipal.getPrivilege((string)clientInfo.get("privilegeName")) < Privileges.Edit;
			else if (string.Compare(usage, "dontuse", true) == 0)
				getKey = false;

			if (getKey)
				key = context.RuleGroup.execute(context, "generateRandomString", clientInfo).CallResults as string;

			return key;
		}

		public string generateRandomString(IApplication app, IRuleContext context, IBizObj clientInfo)
		{
			RandomStringGenerator g = new RandomStringGenerator(5, 7, null, false);
			return g.generateRandomString();
		}
	}
}
